﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class AudioManager : MonoSingleton<AudioManager> {

	private const int MaxSoundNum = 10;

	private GameAudioSource BackgroundMusic;

	private List<GameAudioSource> SoundList = new List<GameAudioSource>();

	private bool muteSound;

	private bool muteMusic;

	private bool GamePaused;

	public float BackgroundMusicVolume
	{
		get
		{
			return (this.BackgroundMusic != null) ? this.BackgroundMusic.Volume : -1f;
		}
		set
		{
			if (this.BackgroundMusic != null)
			{
				this.BackgroundMusic.Volume = value;
			}
		}
	}

	public float BackgroundMusicPitch
	{
		get
		{
			return (this.BackgroundMusic != null) ? this.BackgroundMusic.Pitch : -1f;
		}
		set
		{
			if (this.BackgroundMusic != null)
			{
				this.BackgroundMusic.Pitch = value;
			}
		}
	}

	public bool MuteMusic
	{
		get
		{
			return this.muteMusic;
		}
		set
		{
			if (this.muteMusic != value)
			{
				this.muteMusic = value;
				this.BackgroundMusic.Mute = this.muteMusic;
			}
		}
	}

	public bool MuteSound
	{
		get
		{
			return this.muteSound;
		}
		set
		{
			if (this.muteSound != value)
			{
				this.muteSound = value;
				for (int i = 0; i < this.SoundList.Count; i++)
				{
					GameAudioSource audioSource = this.SoundList[i];
					if (audioSource.IsPlaying)
					{
						audioSource.Mute = this.muteSound;
					}
				}
			}
		}
	}

	protected override void Awake ()
	{
		base.Awake ();
		BackgroundMusic = new GameAudioSource (gameObject.AddComponent<AudioSource> ());
		BackgroundMusic.PlayOnAwake = false;

		EventBus.Instance.AddEventHandler<bool>(EventID.SET_AUDIO_MUSIC_CHANGE, OnMusicMuteChange);
		EventBus.Instance.AddEventHandler<bool>(EventID.SET_AUDIO_SOUND_CHANGE, OnSoundMuteChange);

        EventBus.Instance.AddEventHandler(EventID.GAME_PAUSE, OnGamePause);
        EventBus.Instance.AddEventHandler(EventID.GAME_RESUME, OnGameResume);
    }

	private void OnMusicMuteChange(bool muted) {
		this.MuteMusic = muted;
	}

	private void OnSoundMuteChange(bool muted) {
		this.MuteSound = muted;
	}

    private void OnGamePause()
    {
        this.MuteMusic = true;
        this.MuteSound = true;
    }

    private void OnGameResume()
    {
        this.MuteMusic = AudioSetManager.Instance.MusicMuted;
        this.MuteSound = AudioSetManager.Instance.SoundMuted;
    }

	protected override void OnDestroy ()
	{
		base.OnDestroy ();
		EventBus.Instance.RemoveEventHandler<bool>(EventID.SET_AUDIO_MUSIC_CHANGE, OnMusicMuteChange);
		EventBus.Instance.RemoveEventHandler<bool>(EventID.SET_AUDIO_SOUND_CHANGE, OnSoundMuteChange);
        EventBus.Instance.RemoveEventHandler(EventID.GAME_PAUSE, OnGamePause);
        EventBus.Instance.RemoveEventHandler(EventID.GAME_RESUME, OnGameResume);
    }

	void Start() {
		this.MuteMusic = AudioSetManager.Instance.MusicMuted;
		this.MuteSound = AudioSetManager.Instance.SoundMuted;
	}

	private void OnApplicationPause(bool paused)
	{
		this.GamePaused = paused;
	}

	public AudioClip GetAudioClip(string name) {
		Resource r = ResourceManager.Instance.GetResource (name, typeof(AudioClip), enResourceType.Sound, false, false);
		ResourceManager.Instance.RemoveCachedResource (name);
		return r.m_content as AudioClip;
    }

    public void GetAudioClipAsync(string name, System.Action<AudioClip> callback)
    {
        ResourceManager.Instance.GetResourceAsync(name, typeof(AudioClip), enResourceType.Sound, (res)=> {
            ResourceManager.Instance.RemoveCachedResource(name);
            if (callback != null)
                callback(res.m_content as AudioClip);
        });
    }

    #region music
    public void PlayMusic(AudioClip audioClip, bool loop, bool resumeIfPaused, bool StopOnSceneChange, float StartAtTime) {
		if (this.GamePaused)
			return;

		if (!resumeIfPaused || this.BackgroundMusic.Clip == null || this.BackgroundMusic.Clip.name != audioClip.name) {
			this.BackgroundMusic.Clip = audioClip;
		}
		this.BackgroundMusic.Loop = loop;
		this.BackgroundMusic.Mute = this.MuteMusic;
		this.BackgroundMusic.Play (resumeIfPaused, StopOnSceneChange, StartAtTime);
	}

	public void PlayMusic(string name, bool loop)
	{
		this.PlayMusic(name, loop, false);
	}

	public void PlayMusic(string name, bool loop, bool resumeIfPaused)
	{
		this.PlayMusic(name, loop, resumeIfPaused, true);
	}

	public void PlayMusic(string name, bool loop, bool resumeIfPaused, bool stopOnSceneChange)
	{
        AudioClip clip = this.GetAudioClip(name);
        if (clip == null)
        {
            Debug.LogError("get audio clip error! name:" + name);
            //return;
        }

        this.PlayMusic(this.GetAudioClip(name), loop, resumeIfPaused, stopOnSceneChange);
    }

    public void PlayMusicAsync(string name, bool loop, bool resumeIfPaused, bool stopOnSceneChange)
    {
        this.GetAudioClipAsync(name, (clip)=> {

            if (clip != null)
            {
                this.PlayMusic(clip, loop, resumeIfPaused, stopOnSceneChange);
            }
            else
            {
                Debug.LogError("get audio clip error! name:" + name);
            }
        });

    }

    public void PlayMusic(AudioClip audioClip, bool loop)
	{
		this.PlayMusic(audioClip, loop, false);
	}

	public void PlayMusic(AudioClip audioClip, bool loop, bool resumeIfPaused)
	{
		this.PlayMusic(audioClip, loop, resumeIfPaused, true);
	}

	public void PlayMusic(AudioClip audioClip, bool loop, bool resumeIfPaused, bool stopOnSceneChange)
	{
		this.PlayMusic(audioClip, loop, resumeIfPaused, stopOnSceneChange, 0f);
	}

	public void PlayMusic(List<string> list, bool loop)
	{
		this.PlayMusic(list, loop, false);
	}

	public void PlayMusic(List<string> list, bool loop, bool resumeIfPaused)
	{
		this.PlayMusic(list, loop, resumeIfPaused, true);
	}

	public void PlayMusic(List<string> list, bool loop, bool resumeIfPaused, bool stopOnSceneChange)
	{
		string name = list[StaticRandom.Next() % list.Count];
		this.PlayMusic(name, loop, resumeIfPaused, stopOnSceneChange);
	}

	public void PlayMusic(List<AudioClip> list, bool loop)
	{
		AudioClip audioClip = list[StaticRandom.Next() % list.Count];
		this.PlayMusic(audioClip, loop);
	}

	public bool IsPlayingBackgroundMusic()
	{
		return this.BackgroundMusic.IsPlaying;
	}

	public void PauseBackgroudMusic()
	{
		this.BackgroundMusic.Pause();
	}

	public void StopBackgroundMusic()
	{
		this.StopBackgroundMusic(true, true);
	}

	public void StopBackgroundMusic(bool force, bool sceneChanged)
	{
		if (base.gameObject != null && base.gameObject.activeSelf)
		{
			base.StopAllCoroutines();
		}
		if (this.BackgroundMusic != null && (force || this.BackgroundMusic.StopOnSceneChange == sceneChanged))
		{
			this.BackgroundMusic.Stop();
			this.BackgroundMusic.Clip = null;
		}
	}
	#endregion

	#region Sound
	public GameAudioSource PlaySound(AudioClip clip, float pitch, bool stopOnSceneChange, float volume, bool loop = false)
	{
		if (this.GamePaused)
		{
			return null;
		}
		GameAudioSource audioSource = null;
		for (int i = 0; i < this.SoundList.Count; i++)
		{
			GameAudioSource audioSource2 = this.SoundList[i];
			if (audioSource2 != null && !audioSource2.IsPlaying)
			{
				audioSource = audioSource2;
				break;
			}
		}
		if (audioSource != null)
		{
			this.SoundList.Remove(audioSource);
		}
		else
		{
			if (this.SoundList.Count >= MaxSoundNum)
			{
				this.SoundList[this.SoundList.Count - 1].Stop();
				audioSource = this.SoundList[this.SoundList.Count - 1];
				this.SoundList.RemoveAt(this.SoundList.Count - 1);
			}
			if (audioSource == null)
			{
				audioSource = new GameAudioSource(base.gameObject.AddComponent<AudioSource>());
			}
		}
		this.SoundList.Insert(0, audioSource);
		this.SoundList[0].Clip = clip;
		this.SoundList[0].PlayOnAwake = false;
		this.SoundList[0].Loop = loop;
		this.SoundList[0].Mute = this.MuteSound;
		//播放速度
		this.SoundList[0].Pitch = pitch;
		this.SoundList[0].Volume = volume;
		this.SoundList[0].Play(stopOnSceneChange);

		return this.SoundList [0];
	}

	public GameAudioSource PlaySound(string name)
	{
		return this.PlaySound(name, true);
    }

    public GameAudioSource PlaySound(string name, bool stopOnSceneChange)
    {
        AudioClip audioClip = this.GetAudioClip(name);
        if (audioClip == null)
        {
            Debug.LogError("get audio error! path:" + name);
            //return new GameAudioSource(null);
        }
		return this.PlaySound(audioClip, 1f, stopOnSceneChange);
    }

    public GameAudioSource PlaySound(string name, bool loop, bool stopOnSceneChange)
    {
        AudioClip audioClip = this.GetAudioClip(name);
        if (audioClip == null)
        {
            Debug.LogError("get audio error! path:" + name);
            //return new GameAudioSource(null);
        }
        return this.PlaySound(audioClip, 1f, stopOnSceneChange, 1, loop);
    }

    public GameAudioSource PlaySound(AudioClip[] clip)
	{
		return this.PlaySound(StaticRandom.NextElement<AudioClip>(clip));
	}

	public GameAudioSource PlaySound(AudioClip clip)
	{
		return this.PlaySound(clip, 1f);
	}

	public GameAudioSource PlaySound(AudioClip clip, bool loop) {
		return this.PlaySound (clip, 1f, true, 1, loop);
	}

	public void PlaySound(AudioClip clip, float pitch, float delay)
	{
		base.StartCoroutine(this.PlayDelayed(clip, delay, pitch));
	}

	public GameAudioSource PlaySound(AudioClip clip, float pitch)
	{
		return this.PlaySound(clip, pitch, true);
	}

	public void PlaySound(List<string> list, float delay)
	{
		base.StartCoroutine(this.PlayDelayed(list, delay));
	}

	public GameAudioSource PlaySound(List<string> list)
	{
		return this.PlaySound(list, true);
	}

	public GameAudioSource PlaySound(List<string> list, bool stopOnSceneChange)
	{
		string name = list[StaticRandom.Next() % list.Count];
		return this.PlaySound(name, stopOnSceneChange);
	}

	public GameAudioSource PlaySound(List<AudioClip> list)
	{
		AudioClip clip = list[StaticRandom.Next() % list.Count];
		return this.PlaySound(clip);
	}

	public GameAudioSource PlaySound(AudioClip clip, float pitch, bool stopOnSceneChange)
	{
		return this.PlaySound(clip, pitch, stopOnSceneChange, 1f);
	}

	private IEnumerator PlayDelayed(AudioClip clip, float delay, float pitch) {
		yield return new WaitForSeconds (delay);
		this.PlaySound (clip, pitch);
	}

	private IEnumerator PlayDelayed(List<string> list, float delay) {
		yield return new WaitForSeconds (delay);
		this.PlaySound (list, delay);
	}

	public bool IsPlayingSound()
	{
		for (int i = 0; i < this.SoundList.Count; i++)
		{
			if (this.SoundList[i].IsPlaying)
			{
				return true;
			}
		}
		return false;
	}

	public bool IsPlayingSoundClip(AudioClip audioClip)
	{
		for (int i = 0; i < this.SoundList.Count; i++)
		{
			if (this.SoundList[i].IsPlaying && this.SoundList[i].Clip == audioClip)
			{
				return true;
			}
		}
		return false;
	}

	public void StopSound(GameAudioSource source) {
		if (source != null) {
			source.Stop ();
		}
	}
    public void StopSound(AudioClip audioClip)
    {
        for (int i = 0; i < this.SoundList.Count; i++)
        {
            if (this.SoundList[i].IsPlaying && this.SoundList[i].Clip == audioClip)
            {
                this.SoundList[i].Stop();
            }
        }
    }

    public void StopAllSound()
	{
		this.StopAllSound(true, true);
	}

	public void StopAllSound(bool forceStop, bool sceneChanged)
	{
		base.StopAllCoroutines();
		if (this.SoundList != null)
		{
			for (int i = 0; i < this.SoundList.Count; i++)
			{
				if (forceStop || this.SoundList[i].StopOnSceneChange == sceneChanged)
				{
					this.SoundList[i].Stop();
					this.SoundList[i].Clip = null;
				}
			}
		}
	}
	#endregion

	#region All
	public bool IsPlaying()
	{
		if (this.IsPlayingSound())
		{
			return true;
		}
		return this.IsPlayingBackgroundMusic();
	}

	public void StopAllSounds()
	{
		this.StopBackgroundMusic();
		this.StopAllSound();
	}

	public void StopSoundAndBackgroundSoundsOnSceneChange()
	{
		this.StopAllSound(false, true);
		this.StopBackgroundMusic(false, true);
	}
	#endregion
}
